home *** CD-ROM | disk | FTP | other *** search
/ Programmer Power Tools / Programmer Power Tools.iso / info / memlist.arc / MEMLIST.ASM next >
Assembly Source File  |  1988-09-04  |  12KB  |  418 lines

  1. comment |
  2.  
  3.     This program unravels DOS's (on most machines, Versions 2.0 up to 3.3)
  4.     memory control blocks (MCBs) and prints the information it finds.
  5.     If run under DOS 3.0 or later, it will also print the name it can
  6.     find for each program in memory. The commenting and wording of
  7.     printing messages have been changed in a number of places.
  8.  
  9.     DOS allocates blocks in 16-byte paragraphs, so shift the Block size
  10.     reported by the program 4 bits left (multiply by 16!) to determine
  11.     the actual block length in bytes.
  12.  
  13.     Microsoft has never officially documented how MSDOS allocates memory,
  14.     so much of this program is based on techniques others have discovered.
  15.  
  16.     MCB format:
  17.  
  18.       Byte Offset            Description
  19.     -----------------------------------------------------------------------
  20.  
  21.           0                contains byte 'M' if other MCBs higher
  22.                     in memory, 'Z' if highest current MCB.
  23.  
  24.         1 - 2            PID of block owner (identical to seg
  25.                     addr of the program's program segment
  26.                     prefix [PSP]).
  27.  
  28.         3 - 4            length of block in 16-byte paragraphs.
  29.  
  30.  
  31.     Written for MASM 5.0 by Hardin Brothers for PCResource. The original
  32.     appeared in the July 1988 issue of their magazine. Entire contents of
  33.     the July 1988 issue (C) Copyright 1988 by
  34.                 IDG Communications/Peterborough, Inc.
  35.  
  36.     Hardin Brothers is a freelance programmer and technical writer. Write
  37.     to him at 280 N. Campus Ave., Upland, CA  91786. Enclose a self-
  38.     addressed, stamped envelope for a reply.
  39.  
  40.     |
  41.  
  42. LF    equ    0Ah    ; linefeed char
  43. CR    equ    0Dh    ; carriage return char
  44. STDOUT    equ    1    ; standard output device
  45.  
  46. PRINT    macro    text
  47.     mov    AH, 40h        ; INT 21h service 40h: write to device/file
  48.     mov    BX, STDOUT    ; send message to std output
  49.     lea    DX, &text&msg    ; DS:DX gets address of message string Xmsg
  50.     mov    CX, &text&len    ; get length of message
  51.     int    21h        ; call DOS service
  52.     endm
  53.  
  54. EXIT    macro    val
  55.     mov    AH, 4Ch        ; INT 21h service 4Ch: exit from program
  56.                 ; also returns a value. replaces old INT 20h.
  57.     mov    AL, val        ; return value byte
  58.     int    21h
  59.     endm
  60.  
  61.     .MODEL    SMALL
  62.     .STACK
  63.     .DATA
  64. ourpid        dw    ?
  65. maxmem        dw    ?
  66. basepsp        dw    ?
  67. DosVer        dw    ?
  68. DosV3        db    0
  69.  
  70. NoV1msg        db    'This program cannot be used with DOS Ver. 1.x', CR, LF
  71. NoV1len        equ    $-NoV1msg
  72.  
  73. VERmsg        db    'Unknown DOS version -- cannot find head of memory'
  74.         db    ' chain.', CR, LF
  75. VERlen        equ    $-VERmsg
  76.  
  77. LERRmsg        db    "There apparently in an error with this program's"
  78.         db    ' MCB.', CR, LF
  79. LERRlen        equ    $-LERRmsg
  80.  
  81. ERRmsg        db    'Memory allocation error -- Illegal MCB found.', CR, LF
  82. ERRlen        equ    $-ERRmsg
  83.  
  84. HDRmsg        db    CR, LF, CR, LF
  85.         db    '  MCB     Block     Block     Block     Block'
  86.         db    '     Process', CR, LF
  87.         db    '  Seg     Seg       Owner     Size      Type '
  88.         db    '     Name   ', CR, LF
  89.         db    ' --------------------------------------------'
  90.         db    '------------', CR, LF
  91. HDRlen        equ    $-HDRmsg
  92.  
  93. mcbmsg        db    '  '
  94. mcbadr        db    '0000    '
  95. blkadr        db    '0000      '
  96. blkown        db    '0000      '
  97. blksiz        db    '0000      '
  98. mcblen        equ    $-mcbmsg
  99.  
  100. CRLFmsg        db    CR, LF
  101. CRLFlen        equ    $-CRLFmsg
  102.  
  103. PRGmsg        db    'Prog    '
  104. PRGlen        equ    $-PRGmsg
  105.  
  106. ENVmsg        db    'Envr    '
  107. ENVlen        equ    $-ENVmsg
  108.  
  109. OTHmsg        db    'Data?   '
  110. OTHlen        equ    $-OTHmsg
  111.  
  112. hexlist        db    '0123456789ABCDEF'
  113.  
  114. memMSG        db    CR, LF, CR, LF
  115.         db    'Top of memory: '
  116. memSIZ        db    '0000h.', CR, LF
  117.         db    'Next program will load at: '
  118. memLOC        db    '0000h.', CR, LF, CR, LF
  119.         db    'Memory available: '
  120. memAVL        db    '00000h bytes.', CR, LF, CR, LF
  121. memlen        equ    $-memMSG
  122.  
  123.     .CODE
  124. start:    cld
  125.     mov    AX, @data
  126.     mov    DS, AX        ; set DS to "our" data seg
  127.     mov    AH, 30h        ; INT 21h service 30h: Get DOS Version
  128.     int    21h
  129.     mov    DosVer, AX    ; save entire version number
  130.     cmp    al, 2        ; at least DOS version 2.x ?
  131.     jae    verOK        ; if so, continue...
  132.     PRINT    NoV1        ; else complain about it
  133.     EXIT    -1        ; and quit
  134.  
  135. verOK:    sub    AL, 2        ; test for version 3.x
  136.     mov    DosV3, AL    ; save result (0 or >0) as a flag
  137.  
  138.     mov    BX, 2        ; addr PSP:2 contains maxmem
  139.     mov    AX, ES:[BX]
  140.     mov    maxmem, AX
  141.     push    ES
  142.     mov    AX, ES        ; get addr of "our" PSP
  143.     mov    ourpid, AX    ; save PSP
  144.     dec    AX        ; point to "our" MCB
  145.     mov    ES, AX        ; ES now points to our MCB
  146.     mov    BX, 1        ; offset of PID in our MCB
  147.     inc    AX        ; AX contains our PID again
  148.  
  149.     cmp    AX, word ptr ES:[BX]
  150.     jz    okay        ; if not both the same, something's wrong!
  151.     PRINT    LERR
  152.     EXIT    -1
  153.  
  154. okay:    pop    ES        ; ES points to our PSP
  155.     call    findStart    ; get head of memory chain
  156.  
  157. ;----------------
  158. ;    ES now points to the PSP in lowest memory, which ordinarily belongs
  159. ;    to the first and only copy of COMMAND.COM. This PSP will be used as
  160. ;    the place to begin the trek through memory.
  161. ;----------------
  162.  
  163.     PRINT    HDR        ; output table column headers
  164. rB1:    push    ES        ; save ES
  165.     call    printMCB    ; print memory block info
  166.     mov    AX, ES        ; put MCB seg in AX
  167.     inc    AX        ; AX contains block seg
  168.     mov    ES, AX        ; ES points to memory block
  169.     call    printTYPE    ; print block type
  170.     jc    rB2        ; skip to rB2 if type not ENVR
  171.     test    DosV3, -1    ; using Version 3.x or later?
  172.     jz    rB2        ; skip to rB2 if not
  173.     call    printCMD    ; print program name if found
  174.  
  175. rB2:    PRINT    CRLF        ; terminate output line
  176.     pop    ES        ; ES points to current MCB
  177.     mov    BX, 0        ; addr ES:BX points to block type (M or Z)
  178.  
  179.     cmp    byte ptr ES:[BX], 'Z'    ; at tail of memory chain?
  180.     jz    rB3            ; skip to rB3 if at tail
  181.     mov    AX, ES        ; get current MCB seg
  182.     inc    AX        ; AX contians block seg
  183.     mov    BX, 3        ; addr ES:BX points to block size
  184.     add    AX, ES:[BX]    ; addr block size
  185.     mov    ES, AX        ; ES points to next MCB
  186.     jmp    rB1        ; traverse chain. loop back.
  187.  
  188. rB3:    call    printMEM    ; print memory info
  189.     EXIT    0        ; and terminate program
  190.  
  191. ;----------------
  192. ;    Find the head of the MCB list.
  193. ;    This is the trickiest part of the program, as it is rarely
  194. ;    documented. Method used was created by Ted Mirecki, and was published
  195. ;    in the October 1987 issue of PC Tech Journal.
  196. ;----------------
  197.  
  198. findStart    proc    near
  199.     mov    AX, 0        ; start with seg 0
  200.     mov    ES, AX        ;  in ES
  201.     mov    BX, 0C3h    ; find seg of resident DOS
  202.     mov    AX, ES:[BX]    ; put the seg in AX
  203.     mov    ES, AX        ; ES points to resident DOS seg
  204.     mov    AX, DosVer    ; get DOS Version
  205.     xchg    AH, AL        ; Ver major in AH, minor in AL
  206.     mov    BX, 10Ah    ; offset for Ver 2.0
  207.     cmp    AX, 0209h    ; is this Ver 2.00 - 2.09 ?
  208.     jbe    fS2        ; skip to fS2 if so
  209.     mov    BX, 0F6h    ; offset for Ver 2.1
  210.     cmp    AX, 0213h    ; is this Ver 2.10 - 2.19 ?
  211.     jbe    fS2        ; skip to fS2 if so
  212.     cmp    AL, 2        ; is this some unknown Ver 2.x ?
  213.     jne    fS1        ; skip to fS1 if not
  214.     PRINT    VER
  215.     EXIT    -1
  216.  
  217. fS1:    mov    BX, 128h    ; offset for Ver 3.0
  218.     cmp    AX, 0309h    ; is this Ver 3.00 - 3.09 ?
  219.     jbe    fS2        ; skip to fS2 if so
  220.     mov    BX, 22h        ; offset for Ver 3.10 - 3.30
  221.  
  222. fS2:    les    BX, ES:[BX]    ; get head of memory chain
  223.     ret
  224. findStart    endp
  225.  
  226. comment    |
  227. ;----------------
  228. ;    This is an alternate method of finding the head of the MCB list.
  229. ;    This method will trace backwards to the last copy of COMMAND.COM
  230. ;    installed in memory, and should work if the preceding method does
  231. ;    not with your version of MSDOS.
  232. ;----------------
  233.  
  234. findStart    proc    near
  235.     mov    BX, 16h        ; addr PSP:16h points to parental PSP
  236. fS1:    mov    AX, ES:[BX]    ; get addr of parental PSP
  237.     cmp    AX, 0        ; at tail of chain ? (1st test)
  238.     jz    fS2        ; skip to fS2 if so
  239.     cmp    AX, basepsp    ; at tail of chain ? (2nd test)
  240.     jz    fS2        ; skip to fS2 if so
  241.     mov    basepsp, AX    ; if not, save this value
  242.     mov    ES, AX        ; ES points to parental PSP
  243.     jmp    fS1        ; loop back. traverse chain.
  244.  
  245. fS2:    mov    AX, ES        ; get current PSP seg
  246.     dec    AX        ; AX is seg of MCB
  247.     mov    ES, AX        ; ES points to head of memory chain (1st MCB)
  248.     ret
  249. findStart    endp
  250.     |
  251.  
  252. ;----------------
  253. ;    ES points to a MCB. Print the information contained in the MCB.
  254. ;----------------
  255.  
  256. printMCB    proc    near
  257.     mov    AX, ES        ; AX is seg of MCB
  258.     lea    DI, mcbadr    ; DI points to message area
  259.     call    hextoasc    ; convert AX to ASCII
  260.     inc    AX        ; AX is block addr
  261.     lea    DI, blkadr
  262.     call    hextoasc
  263.     mov    BX, 0        ; is this really a block ?
  264.     mov    AL, ES:[BX]    ; get first byte
  265.     cmp    AL, 'M'        ; part of chain ?
  266.     je    pM1        ; skip to pM1 if so
  267.     cmp    AL, 'Z'        ; tail of chain ?
  268.     je    pM1        ; skip to pM1 if so
  269.     PRINT    ERR        ; else notify error
  270.     EXIT    -1        ; and terminate program
  271.  
  272. pM1:    mov    BX, 1        ; addr ES:BX points to block PID
  273.     mov    AX, ES:[BX]    ; get block PID
  274.     lea    DI, blkown
  275.     call    hextoasc
  276.     mov    BX, 3        ; addr ES:BX points to block size
  277.     mov    AX, ES:[BX]    ; get block size
  278.     lea    DI, blksiz
  279.     call    hextoasc
  280.     PRINT    mcb
  281.     ret
  282. printMCB    endp
  283.  
  284. ;----------------
  285. ;    ES points to a memory block. Determine if it is a PSP, ENVR, or
  286. ;    unknown block. Note that the test for a PSP block checks if the
  287. ;    first 4 bytes of the block are ASCII, so a data block could con-
  288. ;    ceivably show up as a PSP.
  289. ;----------------
  290.  
  291. printTYPE    proc    near
  292.     mov    BX, 0        ; addr ES:BX points to head of block
  293.  
  294.     cmp    byte ptr ES:[BX], 0CDh    ; a PSP always starts at CDh
  295.     jnz    typ1        ; no PSP here, skip to typ1
  296.     PRINT    PRG
  297.     stc            ; set carry flag
  298.     ret
  299.  
  300. typ1:    mov    CX, 4        ; test count of 4 chars
  301. typ2:    mov    AL, ES:[BX]    ; get a byte
  302.     cmp    AL, ' '        ; check for CTRL code
  303.     jb    typ3        ; skip to typ3 if so
  304.     cmp    AL, 'a'        ; check lowercase
  305.     jae    typ3        ; skip to typ3 if so
  306.     inc    BX        ; otherwise point to next byte
  307.     loop    typ2        ; and continue
  308.     PRINT    ENV        ; must be ENVR block type
  309.     clc            ; clear carry flag
  310.     ret
  311.  
  312. typ3:    PRINT    OTH        ; unknown block type
  313.     stc            ; set carry flag
  314.     ret
  315. printTYPE    endp
  316.  
  317. ;----------------
  318. ;    ES points to an environment segment. Scan the segment and print the
  319. ;    name of the program reported to own this environment. The procedure
  320. ;    will only work with DOS Ver 3.0 and later.
  321. ;----------------
  322.  
  323. printCMD    proc    near
  324.     push    DS        ; save data seg
  325.     push    ES        ; copy ES
  326.     pop    DS        ;   to DS
  327.     mov    SI, 0        ; addr DS:SI points to environ text
  328.     mov    CX, 8000h    ; max. size of environ = 32768 bytes
  329.     mov    AX, 0        ; init AX for search
  330.  
  331. pC1:    lodsb            ; get byte in AL, incr SI
  332.     or    AX, AX        ; set flags. test AX.
  333.     jz    pC2        ; AX empty, found start of CMD
  334.     mov    AH, AL        ; AX not empty, save byte
  335.     loop    pC1        ; and get next byte
  336.  
  337. pC1a:    pop    DS        ; nothing found. restore DS
  338.     ret
  339.  
  340. pC2:    lodsw            ; get next word in AX, incr SI
  341.     cmp    AX, 1        ; ought to be 0001h
  342.     jne    pC1a        ; skip to pC1a if not
  343.     mov    DX, SI        ; save start addr
  344.     mov    CX, 0        ; ready byte count
  345.  
  346. pC3:    lodsb            ; get next byte, incr SI
  347.     inc    CX        ; incr byte count
  348.     cmp    AL, ' '        ; end of string?
  349.     ja    pC3        ; loop if not
  350.     mov    BX, STDOUT    ; get ready to print
  351.     mov    AH, 40h        ; INT 21h service 40h: write to file/device
  352.     int    21h
  353.     pop    DS        ; restore DS
  354.     ret
  355. printCMD    endp
  356.  
  357. ;----------------
  358. ;    Print memory block information.
  359. ;----------------
  360.  
  361. printMEM    proc    near
  362.     mov    AX, maxmem
  363.     lea    DI, memSIZ
  364.     call    hextoasc
  365.     mov    AX, ourpid
  366.     lea    DI, memLOC
  367.     call    hextoasc
  368.     mov    AX, maxmem
  369.     sub    AX, ourpid
  370.     lea    DI, memAVL
  371.     call    hextoasc
  372.     PRINT    mem
  373.     ret
  374. printMEM    endp
  375.  
  376. ;----------------
  377. ;    Put value in AX as ASCII-Hex into location at addr DS:DI
  378. ;    Note: procedure can only alter DI
  379. ;----------------
  380.  
  381. hextoasc    proc    near
  382.     push    AX
  383.     push    BX
  384.     push    CX        ; Save registers
  385.     push    ES        ; Save ES
  386.     push    DS        ; Copy DS
  387.     pop    ES        ;   to ES
  388.     lea    BX, hexlist    ; addr DS:BX points to list of hex chars
  389.     xchg    AH, AL        ; swap bytes
  390.     call    hexbyte        ; process one byte
  391.     xchg    AH, AL        ; swap bytes back
  392.     call    hexbyte        ; process other byte
  393.     pop    ES        ; Restore ES
  394.     pop    CX
  395.     pop    BX
  396.     pop    AX        ; Restore registers
  397.     ret
  398.  
  399. hexbyte        proc    near
  400.     push    AX        ; save AL
  401.     and    AL, 0F0h    ; mask low nibble
  402.     mov    CL, 4        ; bit shift count
  403.     shr    AL, CL        ; move high nibble down
  404.     xlat            ; translate nibble to ASCII char
  405.     stosb            ; store char at addr ES:DI, incr DI
  406.     pop    AX        ; restore AL
  407.     push    AX        ; save AX once more
  408.     and    AL, 00Fh    ; mask high nibble
  409.     xlat            ; translate to ASCII
  410.     stosb            ; store char in string
  411.     pop    AX        ; restore AX
  412.     ret
  413. hexbyte        endp
  414. hextoasc    endp
  415.  
  416.     end    start
  417.  
  418.